home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume17 / screen2 / part01 next >
Encoding:
Internet Message Format  |  1989-02-06  |  45.0 KB

  1. Subject:  v17i082:  Screen, multiple windows on a CRT, Part01/02
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4.  
  5. Submitted-by: "Oliver Laumann" <tub!net>
  6. Posting-number: Volume 17, Issue 82
  7. Archive-name: screen2/part01
  8.  
  9. "screen" is a window manager that allows you to handle several independent
  10. screens (UNIX ttys) on a single physical terminal; each screen has its own
  11. set of processes connected to it (typically interactive shells).  Each
  12. virtual terminal created by "screen" emulates a DEC VT100 plus several ANSI
  13. X3.64 and ISO 2022 functions (including DEC VT102 features such as line and
  14. character deletion and insertion).
  15.  
  16. Since "screen" uses pseudo-ttys, the select system call, and UNIX-domain
  17. sockets, it will not run under a system that does not include these
  18. features of 4.2 and 4.3 BSD UNIX.
  19.  
  20. --
  21. Regards,
  22.     Oliver Laumann, Technical University of Berlin, Germany.
  23.     ...!pyramid!tub!net   or   net@TUB.BITNET
  24.  
  25. ----------------------------------------------------------------------------
  26. #! /bin/sh
  27. # This is a shell archive, meaning:
  28. # 1. Remove everything above the #! /bin/sh line.
  29. # 2. Save the resulting text in a file.
  30. # 3. Execute the file with /bin/sh (not csh) to create the files:
  31. #    README
  32. #    Makefile
  33. #    ansi.c
  34. #    screen.h
  35. export PATH; PATH=/bin:$PATH
  36. echo shar: extracting "'README'" '(3987 characters)'
  37. if test -f 'README'
  38. then
  39.     echo shar: will not over-write existing file "'README'"
  40. else
  41. cat << \SHAR_EOF > 'README'
  42. "screen" is a window manager that allows you to handle several independent
  43. screens (UNIX ttys) on a single physical terminal; each screen has its own
  44. set of processes connected to it (typically interactive shells).  Each
  45. virtual terminal created by "screen" emulates a DEC VT100 plus several ANSI
  46. X3.64 and ISO 2022 functions (including DEC VT102 features such as line and
  47. character deletion and insertion).
  48.  
  49. Since "screen" uses pseudo-ttys, the select system call, and UNIX-domain
  50. sockets, it will not run under a system that does not include these
  51. features of 4.2 and 4.3 BSD UNIX.
  52.  
  53. If you want to get a quick idea how "screen" works but don't want to read
  54. the entire manual, do the following:
  55.  
  56.      -  call "screen" without arguments
  57.      -  wait for the shell prompt; execute some commands
  58.      -  type ^A ^C (Control-A followed by Control-C)
  59.      -  wait for the shell prompt; do something in the new window
  60.      -  type ^A ^A repeatedly to switch between the two windows
  61.      -  terminate the first shell ("screen" switches to the other window)
  62.      -  terminate the second shell
  63.  
  64. If you have got "vttest" (the VT100 test program from mod.sources) you
  65. may want to run it from within "screen" to verify that it correctly
  66. emulates a VT100 on your terminal (except for 132 column mode and
  67. double width/height characters, of course).
  68.  
  69. By the way, "screen" can be used to compensate for certain bugs of "real"
  70. VT100 terminals.  For instance, our 4.2 BSD version of mille(6) garbles
  71. the display on terminals of the VT100 family, but it works quite fine
  72. when it is invoked from within "screen".  In addition, "screen" enables
  73. you to use EMACS on terminals that are unable to generate Control-S and
  74. Control-Q from the keyboard or that require flow control using Control-S
  75. and Control-Q.  This is the reason why I have an alias like
  76.      alias emacs "screen emacs"
  77. in my .cshrc file.
  78.  
  79.  
  80. Major changes between this and the previous release are:
  81.  
  82. *  "screen" allows you to `detach' the "screen" session from the physical
  83.    terminal and resume it at a later point in time (possibly on a
  84.    different terminal or in a different login session).
  85.  
  86.   To get an impression of this functionality do the following:
  87.  
  88.      - call "screen" and create a couple of windows
  89.      - type Control-A Control-D (screen terminates; you are back
  90.        in the shell)
  91.      - call "screen -r" to resume the detached "screen"
  92.  
  93. *  "screen" supports multiple character sets and the ISO 2022 control
  94.    functions to designate and switch between character sets.
  95.    This allows you, for instance, to make use of the VT100 graphics
  96.    character set or national character sets
  97.  
  98.  
  99. Before typing "make", you should have a look into the Makefile.
  100. If your system maintains a 4.3-BSD-style load average, add -DLOADAV to
  101. the compiler options.  If the load average maintained by your system
  102. is in the Sun format (three longs; not three doubles), set -DSUNLOADAV
  103. in addition to -DLOADAV.
  104.  
  105. In addition, you must set -DGETTTYENT if your system has the new format
  106. /etc/ttys and the getttyent(3) routines.
  107.  
  108. If the bcopy() from your system's C library supports overlapping
  109. source and destination addresses, add -DUSEBCOPY.  Otherwise screen
  110. uses its own (possibly slower) version of bcopy().  If you are in
  111. doubt or don't know what bcopy() is, leave the option out.
  112.  
  113. "screen" should be granted read and write access to /etc/utmp and, if
  114. -DLOADAV has been specified, read access to /vmunix and /dev/kmem.
  115. "screen" should be installed with set-uid and owner root to enable it
  116. to correctly change the owner of newly allocated virtual terminals.
  117. Failing to do this (e.g. if you fear a trojan horse) doesn't have any
  118. major disadvantages, except that w(1) and some other utilities may have
  119. some problems with the tty files of your virtual terminals.
  120.  
  121.  
  122. Regards,
  123.     Oliver Laumann
  124.     Technical University of Berlin,
  125.     Communications and Operating Systems Research Group.
  126.  
  127.     net@tub.BITNET     US: pyramid!tub!net     Europe: unido!tub!net
  128. SHAR_EOF
  129. if test 3987 -ne "`wc -c < 'README'`"
  130. then
  131.     echo shar: error transmitting "'README'" '(should have been 3987 characters)'
  132. fi
  133. fi # end of overwriting check
  134. echo shar: extracting "'Makefile'" '(1262 characters)'
  135. if test -f 'Makefile'
  136. then
  137.     echo shar: will not over-write existing file "'Makefile'"
  138. else
  139. cat << \SHAR_EOF > 'Makefile'
  140. # The following options can be set:
  141. #
  142. # -DLOADAV    -- your system maintains a load average like 4.3 BSD does
  143. #                (an array of three doubles called _avenrun; it is read
  144. #                from /dev/kmem; _avenrun is taken from the namelist of
  145. #                /vmunix).
  146. # -DSUNLOADAV -- the load average maintained by the kernel is in the
  147. #                Sun format (three longs).  Set this in addition to
  148. #                LOADAV.
  149. # -DGETTTYENT -- your system has the new format /etc/ttys (like 4.3 BSD)
  150. #                and the getttyent(3) library functions.
  151. #
  152. # -DUSEBCOPY  -- use the bcopy() from the system's C-library.  If this
  153. #                is set, bcopy must support overlapping source and
  154. #                destination.  If USEBCOPY is not set, screen uses its
  155. #                own version of bcopy.
  156. #
  157. # You should install as set-uid with owner root, so that it can read/write
  158. # /etc/utmp, read /dev/kmem, and chown/chmod the allocated pseudo-ttys.
  159.  
  160. OPTIONS= -DLOADAV -DSUNLOADAV -DGETTTYENT -DUSEBCOPY
  161.  
  162. CFILES= screen.c ansi.c
  163. OFILES= screen.o ansi.o
  164.  
  165. screen: $(OFILES)
  166.     $(CC) $(CFLAGS) -o screen $(OFILES) -ltermcap
  167.  
  168. screen.o: screen.c screen.h
  169.     $(CC) $(OPTIONS) $(CFLAGS) -c screen.c
  170.  
  171. ansi.o: ansi.c screen.h
  172.     $(CC) $(CFLAGS) -c ansi.c
  173. SHAR_EOF
  174. if test 1262 -ne "`wc -c < 'Makefile'`"
  175. then
  176.     echo shar: error transmitting "'Makefile'" '(should have been 1262 characters)'
  177. fi
  178. fi # end of overwriting check
  179. echo shar: extracting "'ansi.c'" '(35918 characters)'
  180. if test -f 'ansi.c'
  181. then
  182.     echo shar: will not over-write existing file "'ansi.c'"
  183. else
  184. cat << \SHAR_EOF > 'ansi.c'
  185. /* Copyright (c) 1987,1988 Oliver Laumann, Technical University of Berlin.
  186.  * Not derived from licensed software.
  187.  *
  188.  * Permission is granted to freely use, copy, modify, and redistribute
  189.  * this software, provided that no attempt is made to gain profit from it,
  190.  * the author is not construed to be liable for any results of using the
  191.  * software, alterations are clearly marked as such, and this notice is
  192.  * not modified.
  193.  */
  194.  
  195. char AnsiVersion[] = "ansi 2.0a 19-Oct-88";
  196.  
  197. #include <stdio.h>
  198. #include <sys/types.h>
  199. #include "screen.h"
  200.  
  201. #define A_SO     0x1    /* Standout mode */
  202. #define A_US     0x2    /* Underscore mode */
  203. #define A_BL     0x4    /* Blinking */
  204. #define A_BD     0x8    /* Bold mode */
  205. #define A_DI    0x10    /* Dim mode */
  206. #define A_RV    0x20    /* Reverse mode */
  207. #define A_MAX   0x20
  208.  
  209. /* Types of movement used by Goto() */
  210. enum move_t {
  211.     M_NONE,
  212.     M_UP,
  213.     M_DO,
  214.     M_LE,
  215.     M_RI,
  216.     M_RW,
  217.     M_CR,
  218. };
  219.  
  220. #define EXPENSIVE    1000
  221.  
  222. #define G0           0
  223. #define G1           1
  224. #define G2           2
  225. #define G3           3
  226.  
  227. #define ASCII        0
  228.  
  229. extern char *getenv(), *tgetstr(), *tgoto(), *malloc();
  230.  
  231. int rows, cols;
  232. int status;
  233. int flowctl;
  234. char Term[] = "TERM=screen";
  235. char Termcap[1024];
  236. char *blank;
  237. char PC;
  238. int ISO2022;
  239. time_t TimeDisplayed;
  240.  
  241. static char tbuf[1024], tentry[1024];
  242. static char *tp = tentry;
  243. static char *TI, *TE, *BL, *VB, *BC, *CR, *NL, *CL, *IS, *CM;
  244. static char *US, *UE, *SO, *SE, *CE, *CD, *DO, *SR, *SF, *AL;
  245. static char *CS, *DL, *DC, *IC, *IM, *EI, *UP, *ND, *KS, *KE;
  246. static char *MB, *MD, *MH, *MR, *ME, *PO, *PF;
  247. static char *CDC, *CDL, *CAL;
  248. static AM;
  249. static char GlobalAttr, TmpAttr, GlobalCharset, TmpCharset;
  250. static char *OldImage, *OldAttr, *OldFont;
  251. static last_x, last_y;
  252. static struct win *curr;
  253. static display = 1;
  254. static StrCost;
  255. static UPcost, DOcost, LEcost, NDcost, CRcost, IMcost, EIcost;
  256. static tcLineLen = 100;
  257. static char *null;
  258. static StatLen;
  259. static insert;
  260. static keypad;
  261.  
  262. static char *KeyCaps[] = {
  263.     "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7", "k8", "k9",
  264.     "kb", "kd", "kh", "kl", "ko", "kr", "ku",
  265.     0
  266. };
  267.  
  268. static char TermcapConst[] = "TERMCAP=\
  269. SC|screen|VT 100/ANSI X3.64 virtual terminal|\\\n\
  270. \t:DO=\\E[%dB:LE=\\E[%dD:RI=\\E[%dC:UP=\\E[%dA:bs:bt=\\E[Z:\\\n\
  271. \t:cd=\\E[J:ce=\\E[K:cl=\\E[2J\\E[H:cm=\\E[%i%d;%dH:ct=\\E[3g:\\\n\
  272. \t:do=\\E[B:nd=\\E[C:pt:rc=\\E8:rs=\\Ec:sc=\\E7:st=\\EH:up=\\E[A:le=^H:";
  273.  
  274. InitTerm () {
  275.     register char *s;
  276.  
  277.     if ((s = getenv ("TERM")) == 0)
  278.     Msg (0, "No TERM in environment.");
  279.     if (tgetent (tbuf, s) != 1)
  280.     Msg (0, "Cannot find termcap entry for %s.", s);
  281.     cols = tgetnum ("co");
  282.     rows = tgetnum ("li");
  283.     if (cols <= 0)
  284.     cols = 80;
  285.     if (rows <= 0)
  286.     rows = 24;
  287.     if (tgetflag ("hc"))
  288.     Msg (0, "You can't run screen on a hardcopy terminal.");
  289.     if (tgetflag ("os"))
  290.     Msg (0, "You can't run screen on a terminal that overstrikes.");
  291.     if (tgetflag ("ns"))
  292.     Msg (0, "Terminal must support scrolling.");
  293.     if (!(CL = tgetstr ("cl", &tp)))
  294.     Msg (0, "Clear screen capability required.");
  295.     if (!(CM = tgetstr ("cm", &tp)))
  296.     Msg (0, "Addressable cursor capability required.");
  297.     if (s = tgetstr ("ps", &tp))
  298.     PC = s[0];
  299.     flowctl = !tgetflag ("NF");
  300.     AM = tgetflag ("am");
  301.     if (tgetflag ("LP"))
  302.     AM = 0;
  303.     TI = tgetstr ("ti", &tp);
  304.     TE = tgetstr ("te", &tp);
  305.     if (!(BL = tgetstr ("bl", &tp)))
  306.     BL = "\007";
  307.     VB = tgetstr ("vb", &tp);
  308.     if (!(BC = tgetstr ("bc", &tp))) {
  309.     if (tgetflag ("bs"))
  310.         BC = "\b";
  311.     else
  312.         BC = tgetstr ("le", &tp);
  313.     }
  314.     if (!(CR = tgetstr ("cr", &tp)))
  315.     CR = "\r";
  316.     if (!(NL = tgetstr ("nl", &tp)))
  317.     NL = "\n";
  318.     IS = tgetstr ("is", &tp);
  319.     if (tgetnum ("sg") <= 0) {
  320.     US = tgetstr ("us", &tp);
  321.     UE = tgetstr ("ue", &tp);
  322.     SO = tgetstr ("so", &tp);
  323.     SE = tgetstr ("se", &tp);
  324.     MB = tgetstr ("mb", &tp);
  325.     MD = tgetstr ("md", &tp);
  326.     MH = tgetstr ("mh", &tp);
  327.     MR = tgetstr ("mr", &tp);
  328.     ME = tgetstr ("me", &tp);
  329.     /*
  330.      * Does ME also reverse the effect of SO and/or US?  This is not
  331.      * clearly specified by the termcap manual.
  332.      * Anyway, we should at least look whether ME and SE/UE are equal:
  333.      */
  334.     if (SE && UE && ME && (strcmp (SE, UE) == 0 || strcmp (ME, UE) == 0))
  335.         UE = 0;
  336.     if (SE && ME && strcmp (SE, ME) == 0)
  337.         SE = 0;
  338.     }
  339.     CE = tgetstr ("ce", &tp);
  340.     CD = tgetstr ("cd", &tp);
  341.     if (!(DO = tgetstr ("do", &tp)))
  342.     DO = NL;
  343.     UP = tgetstr ("up", &tp);
  344.     ND = tgetstr ("nd", &tp);
  345.     SR = tgetstr ("sr", &tp);
  346.     if (!(SF = tgetstr ("sf", &tp)))
  347.     SF = NL;
  348.     AL = tgetstr ("al", &tp);
  349.     DL = tgetstr ("dl", &tp);
  350.     CS = tgetstr ("cs", &tp);
  351.     DC = tgetstr ("dc", &tp);
  352.     IC = tgetstr ("ic", &tp);
  353.     CDC = tgetstr ("DC", &tp);
  354.     CDL = tgetstr ("DL", &tp);
  355.     CAL = tgetstr ("AL", &tp);
  356.     IM = tgetstr ("im", &tp);
  357.     EI = tgetstr ("ei", &tp);
  358.     if (tgetflag ("in"))
  359.     IC = IM = 0;
  360.     if (IC && IC[0] == '\0')
  361.     IC = 0;
  362.     if (IM && IM[0] == '\0')
  363.     IM = 0;
  364.     if (EI && EI[0] == '\0')
  365.     EI = 0;
  366.     KS = tgetstr ("ks", &tp);
  367.     KE = tgetstr ("ke", &tp);
  368.     ISO2022 = tgetflag ("G0");
  369.     PO = tgetstr ("po", &tp);
  370.     if (!(PF = tgetstr ("pf", &tp)))
  371.     PO = 0;
  372.     blank = malloc (cols);
  373.     null = malloc (cols);
  374.     OldImage = malloc (cols);
  375.     OldAttr = malloc (cols);
  376.     OldFont = malloc (cols);
  377.     if (!(blank && null && OldImage && OldAttr && OldFont))
  378.     Msg (0, "Out of memory.");
  379.     MakeBlankLine (blank, cols);
  380.     bzero (null, cols);
  381.     UPcost = CalcCost (UP);
  382.     DOcost = CalcCost (DO);
  383.     LEcost = CalcCost (BC);
  384.     NDcost = CalcCost (ND);
  385.     CRcost = CalcCost (CR);
  386.     IMcost = CalcCost (IM);
  387.     EIcost = CalcCost (EI);
  388.     PutStr (IS);
  389.     PutStr (TI);
  390.     PutStr (CL);
  391. }
  392.  
  393. FinitTerm () {
  394.     PutStr (TE);
  395.     PutStr (IS);
  396. }
  397.  
  398. static AddCap (s) char *s; {
  399.     register n;
  400.  
  401.     if (tcLineLen + (n = strlen (s)) > 55) {
  402.     strcat (Termcap, "\\\n\t:");
  403.     tcLineLen = 0;
  404.     }
  405.     strcat (Termcap, s);
  406.     tcLineLen += n;
  407. }
  408.  
  409. char *MakeTermcap (aflag) {
  410.     char buf[1024];
  411.     register char **pp, *p;
  412.  
  413.     strcpy (Termcap, TermcapConst);
  414.     sprintf (buf, "li#%d:co#%d:", rows, cols);
  415.     AddCap (buf);
  416.     if (VB)
  417.     AddCap ("vb=\\E[?5h\\E[?5l:");
  418.     if (US) {
  419.     AddCap ("us=\\E[4m:");
  420.     AddCap ("ue=\\E[24m:");
  421.     }
  422.     if (SO) {
  423.     AddCap ("so=\\E[3m:");
  424.     AddCap ("se=\\E[23m:");
  425.     }
  426.     if (MB)
  427.     AddCap ("mb=\\E[5m:");
  428.     if (MD)
  429.     AddCap ("md=\\E[1m:");
  430.     if (MH)
  431.     AddCap ("mh=\\E[2m:");
  432.     if (MR)
  433.     AddCap ("mr=\\E[7m:");
  434.     if (MB || MD || MH || MR)
  435.     AddCap ("me=\\E[0m:");
  436.     if ((CS && SR) || AL || CAL || aflag) {
  437.     AddCap ("sr=\\EM:");
  438.     AddCap ("al=\\E[L:");
  439.     AddCap ("AL=\\E[%dL:");
  440.     }
  441.     if (CS || DL || CDL || aflag) {
  442.     AddCap ("dl=\\E[M:");
  443.     AddCap ("DL=\\E[%dM:");
  444.     }
  445.     if (CS)
  446.     AddCap ("cs=\\E[%i%d;%dr:");
  447.     if (DC || CDC || aflag) {
  448.     AddCap ("dc=\\E[P:");
  449.     AddCap ("DC=\\E[%dP:");
  450.     }
  451.     if (IC || IM || aflag) {
  452.     AddCap ("im=\\E[4h:");
  453.     AddCap ("ei=\\E[4l:");
  454.     AddCap ("ic=:");
  455.     AddCap ("IC=\\E[%d@:");
  456.     }
  457.     if (KS)
  458.     AddCap ("ks=\\E=:");
  459.     if (KE)
  460.     AddCap ("ke=\\E>:");
  461.     if (ISO2022)
  462.     AddCap ("G0:");
  463.     if (PO) {
  464.     AddCap ("po=\\E[5i:");
  465.     AddCap ("pf=\\E[4i:");
  466.     }
  467.     for (pp = KeyCaps; *pp; ++pp)
  468.     if (p = tgetstr (*pp, &tp)) {
  469.         MakeString (*pp, buf, p);
  470.         AddCap (buf);
  471.     }
  472.     return Termcap;
  473. }
  474.  
  475. static MakeString (cap, buf, s) char *cap, *buf; register char *s; {
  476.     register char *p = buf;
  477.     register unsigned c;
  478.  
  479.     *p++ = *cap++; *p++ = *cap; *p++ = '=';
  480.     while (c = *s++) {
  481.     switch (c) {
  482.     case '\033':
  483.         *p++ = '\\'; *p++ = 'E'; break;
  484.     case ':':
  485.         sprintf (p, "\\072"); p += 4; break;
  486.     case '^': case '\\':
  487.         *p++ = '\\'; *p++ = c; break;
  488.     default:
  489.         if (c >= 200) {
  490.         sprintf (p, "\\%03o", c & 0377); p += 4;
  491.         } else if (c < ' ') {
  492.         *p++ = '^'; *p++ = c + '@';
  493.         } else *p++ = c;
  494.     }
  495.     }
  496.     *p++ = ':'; *p = '\0';
  497. }
  498.  
  499. Activate (wp) struct win *wp; {
  500.     RemoveStatus (wp);
  501.     curr = wp;
  502.     display = 1;
  503.     NewRendition (GlobalAttr, curr->LocalAttr);
  504.     GlobalAttr = curr->LocalAttr;
  505.     NewCharset (GlobalCharset, curr->charsets[curr->LocalCharset]);
  506.     GlobalCharset = curr->charsets[curr->LocalCharset];
  507.     if (CS)
  508.     PutStr (tgoto (CS, curr->bot, curr->top));
  509.     Redisplay ();
  510.     KeypadMode (curr->keypad);
  511. }
  512.  
  513. ResetScreen (p) register struct win *p; {
  514.     register i;
  515.  
  516.     bzero (p->tabs, cols);
  517.     for (i = 8; i < cols; i += 8)
  518.     p->tabs[i] = 1;
  519.     p->wrap = 1;
  520.     p->origin = 0;
  521.     p->insert = 0;
  522.     p->vbwait = 0;
  523.     p->keypad = 0;
  524.     p->top = 0;
  525.     p->bot = rows - 1;
  526.     p->saved = 0;
  527.     p->LocalAttr = 0;
  528.     p->x = p->y = 0;
  529.     p->state = LIT;
  530.     p->StringType = NONE;
  531.     p->ss = 0;
  532.     p->LocalCharset = G0;
  533.     for (i = G0; i <= G3; i++)
  534.     p->charsets[i] = ASCII;
  535. }
  536.  
  537. WriteString (wp, buf, len) struct win *wp; register char *buf; {
  538.     register c, intermediate = 0;
  539.  
  540.     if (!len)
  541.     return;
  542.     curr = wp;
  543.     display = curr->active;
  544.     if (display)
  545.     RemoveStatus (wp);
  546.     do {
  547.     c = *buf++;
  548.     if (c == '\0' || c == '\177')
  549.         continue;
  550. NextChar:
  551.     switch (curr->state) {
  552.     case PRIN:
  553.         switch (c) {
  554.         case '\033':
  555.         curr->state = PRINESC; break;
  556.         default:
  557.         PrintChar (c);
  558.         }
  559.         break;
  560.     case PRINESC:
  561.         switch (c) {
  562.         case '[':
  563.         curr->state = PRINCSI; break;
  564.         default:
  565.         PrintChar ('\033'); PrintChar (c);
  566.         curr->state = PRIN;
  567.         }
  568.         break;
  569.     case PRINCSI:
  570.         switch (c) {
  571.         case '4':
  572.         curr->state = PRIN4; break;
  573.         default:
  574.         PrintChar ('\033'); PrintChar ('['); PrintChar (c);
  575.         curr->state = PRIN;
  576.         }
  577.         break;
  578.     case PRIN4:
  579.         switch (c) {
  580.         case 'i':
  581.         curr->state = LIT;
  582.         PrintFlush ();
  583.         break;
  584.         default:
  585.         PrintChar ('\033'); PrintChar ('['); PrintChar ('4');
  586.         PrintChar (c);
  587.         curr->state = PRIN;
  588.         }
  589.         break;
  590.     case TERM:
  591.         switch (c) {
  592.         case '\\':
  593.         curr->state = LIT;
  594.         *(curr->stringp) = '\0';
  595.         if (curr->StringType == PM && display) {
  596.             MakeStatus (curr->string, curr);
  597.             if (status && len > 1) {
  598.             curr->outlen = len-1;
  599.             bcopy (buf, curr->outbuf, curr->outlen);
  600.             return;
  601.             }
  602.         }
  603.         break;
  604.         default:
  605.         curr->state = STR;
  606.         AddChar ('\033');
  607.         AddChar (c);
  608.         }
  609.         break;
  610.     case STR:
  611.         switch (c) {
  612.         case '\0':
  613.         break;
  614.         case '\033':
  615.         curr->state = TERM; break;
  616.         default:
  617.         AddChar (c);
  618.         }
  619.         break;
  620.     case ESC:
  621.         switch (c) {
  622.         case '[':
  623.         curr->NumArgs = 0;
  624.         intermediate = 0;
  625.         bzero ((char *)curr->args, MAXARGS * sizeof (int));
  626.         bzero (curr->GotArg, MAXARGS);
  627.         curr->state = CSI;
  628.         break;
  629.         case ']':
  630.         StartString (OSC); break;
  631.         case '_':
  632.         StartString (APC); break;
  633.         case 'P':
  634.         StartString (DCS); break;
  635.         case '^':
  636.         StartString (PM); break;
  637.         default:
  638.         if (Special (c))
  639.             break;
  640.         if (c >= ' ' && c <= '/') {
  641.             intermediate = intermediate ? -1 : c;
  642.         } else if (c >= '0' && c <= '~') {
  643.             DoESC (c, intermediate);
  644.             curr->state = LIT;
  645.         } else {
  646.             curr->state = LIT;
  647.             goto NextChar;
  648.         }
  649.         }
  650.         break;
  651.     case CSI:
  652.         switch (c) {
  653.         case '0': case '1': case '2': case '3': case '4':
  654.         case '5': case '6': case '7': case '8': case '9':
  655.         if (curr->NumArgs < MAXARGS) {
  656.             curr->args[curr->NumArgs] =
  657.                         10 * curr->args[curr->NumArgs] + c - '0';
  658.             curr->GotArg[curr->NumArgs] = 1;
  659.         }
  660.         break;
  661.         case ';': case ':':
  662.         curr->NumArgs++; break;
  663.         default:
  664.         if (Special (c))
  665.             break;
  666.         if (c >= '@' && c <= '~') {
  667.             curr->NumArgs++;
  668.             DoCSI (c, intermediate);
  669.             if (curr->state != PRIN)
  670.             curr->state = LIT;
  671.         } else if ((c >= ' ' && c <= '/') || (c >= '<' && c <= '?')) {
  672.             intermediate = intermediate ? -1 : c;
  673.         } else {
  674.             curr->state = LIT;
  675.             goto NextChar;
  676.         }
  677.         }
  678.         break;
  679.     default:
  680.         if (!Special (c)) {
  681.         if (c == '\033') {
  682.             intermediate = 0;
  683.             curr->state = ESC;
  684.         } else if (c < ' ') {
  685.             break;
  686.         } else {
  687.             if (curr->ss)
  688.             NewCharset (GlobalCharset, curr->charsets[curr->ss]);
  689.             if (curr->x < cols-1) {
  690.             if (curr->insert) {
  691.                 InsertAChar (c);
  692.             } else {
  693.                 if (display)
  694.                 putchar (c);
  695.                 SetChar (c);
  696.             }
  697.             curr->x++;
  698.             } else if (curr->x == cols-1) {
  699.             SetChar (c);
  700.             if (!(AM && curr->y == curr->bot)) {
  701.                 if (display)
  702.                 putchar (c);
  703.                 Goto (-1, -1, curr->y, curr->x);
  704.             }
  705.             curr->x++;
  706.             } else {
  707.             if (curr->wrap) {
  708.                 Return ();
  709.                 LineFeed ();
  710.                 if (curr->insert) {
  711.                 InsertAChar (c);
  712.                 } else {
  713.                 if (display)
  714.                     putchar (c);
  715.                 SetChar (c);
  716.                 }
  717.                 curr->x = 1;
  718.             } else curr->x = cols;
  719.             }
  720.             if (curr->ss) {
  721.             NewCharset (curr->charsets[curr->ss], GlobalCharset);
  722.             curr->ss = 0;
  723.             }
  724.         }
  725.         }
  726.     }
  727.     } while (--len);
  728.     curr->outlen = 0;
  729.     if (curr->state == PRIN)
  730.     PrintFlush ();
  731. }
  732.  
  733. static Special (c) register c; {
  734.     switch (c) {
  735.     case '\b':
  736.     BackSpace (); return 1;
  737.     case '\r':
  738.     Return (); return 1;
  739.     case '\n':
  740.     LineFeed (); return 1;
  741.     case '\007':
  742.     PutStr (BL);
  743.     if (!display)
  744.         curr->bell = 1;
  745.     return 1;
  746.     case '\t':
  747.     ForwardTab (); return 1;
  748.     case '\017':   /* SI */
  749.     MapCharset (G0); return 1;
  750.     case '\016':   /* SO */
  751.     MapCharset (G1); return 1;
  752.     }
  753.     return 0;
  754. }
  755.  
  756. static DoESC (c, intermediate) {
  757.     switch (intermediate) {
  758.     case 0:
  759.     switch (c) {
  760.     case 'E':
  761.         Return ();
  762.         LineFeed ();
  763.         break;
  764.     case 'D':
  765.         LineFeed (); 
  766.         break;
  767.     case 'M':
  768.         ReverseLineFeed ();
  769.         break;
  770.     case 'H':
  771.         curr->tabs[curr->x] = 1;
  772.         break;
  773.     case '7':
  774.         SaveCursor ();
  775.         break;
  776.     case '8':
  777.         RestoreCursor ();
  778.         break;
  779.     case 'c':
  780.         ClearScreen ();
  781.         Goto (curr->y, curr->x, 0, 0);
  782.         NewRendition (GlobalAttr, 0);
  783.         SetRendition (0);
  784.         NewCharset (GlobalCharset, ASCII);
  785.         GlobalCharset = ASCII;
  786.         if (curr->insert)
  787.         InsertMode (0);
  788.         if (curr->keypad)
  789.         KeypadMode (0);
  790.         if (CS)
  791.         PutStr (tgoto (CS, rows-1, 0));
  792.         ResetScreen (curr);
  793.         break;
  794.     case '=':
  795.         KeypadMode (1);
  796.         curr->keypad = 1;
  797.         break;
  798.     case '>':
  799.         KeypadMode (0);
  800.         curr->keypad = 0;
  801.         break;
  802.     case 'n':   /* LS2 */
  803.         MapCharset (G2); break;
  804.     case 'o':   /* LS3 */
  805.         MapCharset (G3); break;
  806.     case 'N':   /* SS2 */
  807.         if (GlobalCharset == curr->charsets[G2])
  808.         curr->ss = 0;
  809.         else
  810.         curr->ss = G2;
  811.         break;
  812.     case 'O':   /* SS3 */
  813.         if (GlobalCharset == curr->charsets[G3])
  814.         curr->ss = 0;
  815.         else
  816.         curr->ss = G3;
  817.         break;
  818.     }
  819.     break;
  820.     case '#':
  821.     switch (c) {
  822.     case '8':
  823.         FillWithEs ();
  824.         break;
  825.     }
  826.     break;
  827.     case '(':
  828.     DesignateCharset (c, G0); break;
  829.     case ')':
  830.     DesignateCharset (c, G1); break;
  831.     case '*':
  832.     DesignateCharset (c, G2); break;
  833.     case '+':
  834.     DesignateCharset (c, G3); break;
  835.     }
  836. }
  837.  
  838. static DoCSI (c, intermediate) {
  839.     register i, a1 = curr->args[0], a2 = curr->args[1];
  840.  
  841.     if (curr->NumArgs >= MAXARGS)
  842.     curr->NumArgs = MAXARGS;
  843.     for (i = 0; i < curr->NumArgs; ++i)
  844.     if (curr->args[i] == 0)
  845.         curr->GotArg[i] = 0;
  846.     switch (intermediate) {
  847.     case 0:
  848.     switch (c) {
  849.     case 'H': case 'f':
  850.         if (!curr->GotArg[0]) a1 = 1;
  851.         if (!curr->GotArg[1]) a2 = 1;
  852.         if (curr->origin)
  853.         a1 += curr->top;
  854.         if (a1 < 1)
  855.         a1 = 1;
  856.         if (a1 > rows)
  857.         a1 = rows;
  858.         if (a2 < 1)
  859.         a2 = 1;
  860.         if (a2 > cols)
  861.         a2 = cols;
  862.         a1--; a2--;
  863.         Goto (curr->y, curr->x, a1, a2);
  864.         curr->y = a1;
  865.         curr->x = a2;
  866.         break;
  867.     case 'J':
  868.         if (!curr->GotArg[0] || a1 < 0 || a1 > 2)
  869.         a1 = 0;
  870.         switch (a1) {
  871.         case 0:
  872.         ClearToEOS (); break;
  873.         case 1:
  874.         ClearFromBOS (); break;
  875.         case 2:
  876.         ClearScreen ();
  877.         Goto (0, 0, curr->y, curr->x);
  878.         break;
  879.         }
  880.         break;
  881.     case 'K':
  882.         if (!curr->GotArg[0] || a1 < 0 || a1 > 2)
  883.         a1 %= 3;
  884.         switch (a1) {
  885.         case 0:
  886.         ClearToEOL (); break;
  887.         case 1:
  888.         ClearFromBOL (); break;
  889.         case 2:
  890.         ClearLine (); break;
  891.         }
  892.         break;
  893.     case 'A':
  894.         CursorUp (curr->GotArg[0] ? a1 : 1);
  895.         break;
  896.     case 'B':
  897.         CursorDown (curr->GotArg[0] ? a1 : 1);
  898.         break;
  899.     case 'C':
  900.         CursorRight (curr->GotArg[0] ? a1 : 1);
  901.         break;
  902.     case 'D':
  903.         CursorLeft (curr->GotArg[0] ? a1 : 1);
  904.         break;
  905.     case 'm':
  906.         SelectRendition ();
  907.         break;
  908.     case 'g':
  909.         if (!curr->GotArg[0] || a1 == 0)
  910.         curr->tabs[curr->x] = 0;
  911.         else if (a1 == 3)
  912.         bzero (curr->tabs, cols);
  913.         break;
  914.     case 'r':
  915.         if (!CS)
  916.         break;
  917.         if (!curr->GotArg[0]) a1 = 1;
  918.         if (!curr->GotArg[1]) a2 = rows;
  919.         if (a1 < 1 || a2 > rows || a1 >= a2)
  920.         break;
  921.         curr->top = a1-1;
  922.         curr->bot = a2-1;
  923.         PutStr (tgoto (CS, curr->bot, curr->top));
  924.         if (curr->origin) {
  925.         Goto (-1, -1, curr->top, 0);
  926.         curr->y = curr->top;
  927.         curr->x = 0;
  928.         } else {
  929.         Goto (-1, -1, 0, 0);
  930.         curr->y = curr->x = 0;
  931.         }
  932.         break;
  933.     case 'I':
  934.         if (!curr->GotArg[0]) a1 = 1;
  935.         while (a1--)
  936.         ForwardTab ();
  937.         break;
  938.     case 'Z':
  939.         if (!curr->GotArg[0]) a1 = 1;
  940.         while (a1--)
  941.         BackwardTab ();
  942.         break;
  943.     case 'L':
  944.         InsertLine (curr->GotArg[0] ? a1 : 1);
  945.         break;
  946.     case 'M':
  947.         DeleteLine (curr->GotArg[0] ? a1 : 1);
  948.         break;
  949.     case 'P':
  950.         DeleteChar (curr->GotArg[0] ? a1 : 1);
  951.         break;
  952.     case '@':
  953.         InsertChar (curr->GotArg[0] ? a1 : 1);
  954.         break;
  955.     case 'h':
  956.         SetMode (1);
  957.         break;
  958.     case 'l':
  959.         SetMode (0);
  960.         break;
  961.     case 'i':
  962.         if (PO && curr->GotArg[0] && a1 == 5) {
  963.         curr->stringp = curr->string;
  964.         curr->state = PRIN;
  965.         }
  966.         break;
  967.     }
  968.     break;
  969.     case '?':
  970.     if (c != 'h' && c != 'l')
  971.         break;
  972.     if (!curr->GotArg[0])
  973.         break;
  974.     i = (c == 'h');
  975.     if (a1 == 5) {
  976.         if (i) {
  977.         curr->vbwait = 1;
  978.         } else {
  979.         if (curr->vbwait)
  980.             PutStr (VB);
  981.         curr->vbwait = 0;
  982.         }
  983.     } else if (a1 == 6) {
  984.         curr->origin = i;
  985.         if (curr->origin) {
  986.         Goto (curr->y, curr->x, curr->top, 0);
  987.         curr->y = curr->top;
  988.         curr->x = 0;
  989.         } else {
  990.         Goto (curr->y, curr->x, 0, 0);
  991.         curr->y = curr->x = 0;
  992.         }
  993.     } else if (a1 == 7) {
  994.         curr->wrap = i;
  995.     }
  996.     break;
  997.     }
  998. }
  999.  
  1000. static PutChar (c) {
  1001.     putchar (c);
  1002. }
  1003.  
  1004. static PutStr (s) char *s; {
  1005.     if (display && s)
  1006.     tputs (s, 1, PutChar);
  1007. }
  1008.  
  1009. static CPutStr (s, c) char *s; {
  1010.     if (display && s)
  1011.     tputs (tgoto (s, 0, c), 1, PutChar);  /* XXX */
  1012. }
  1013.  
  1014. static SetChar (c) register c; {
  1015.     register struct win *p = curr;
  1016.  
  1017.     p->image[p->y][p->x] = c;
  1018.     p->attr[p->y][p->x] = p->LocalAttr;
  1019.     p->font[p->y][p->x] = p->charsets[p->ss ? p->ss : p->LocalCharset];
  1020. }
  1021.  
  1022. static StartString (type) enum string_t type; {
  1023.     curr->StringType = type;
  1024.     curr->stringp = curr->string;
  1025.     curr->state = STR;
  1026. }
  1027.  
  1028. static AddChar (c) {
  1029.     if (curr->stringp >= curr->string+MAXSTR-1)
  1030.     curr->state = LIT;
  1031.     else
  1032.     *(curr->stringp)++ = c;
  1033. }
  1034.  
  1035. static PrintChar (c) {
  1036.     if (curr->stringp >= curr->string+MAXSTR-1)
  1037.     PrintFlush ();
  1038.     else
  1039.     *(curr->stringp)++ = c;
  1040. }
  1041.  
  1042. static PrintFlush () {
  1043.     if (curr->stringp > curr->string) {
  1044.     tputs (PO, 1, PutChar);
  1045.     (void) fflush (stdout);
  1046.     (void) write (1, curr->string, curr->stringp - curr->string);
  1047.     tputs (PF, 1, PutChar);
  1048.     (void) fflush (stdout);
  1049.     curr->stringp = curr->string;
  1050.     }
  1051. }
  1052.  
  1053. /* Insert mode is a toggle on some terminals, so we need this hack:
  1054.  */
  1055. static InsertMode (on) {
  1056.     if (on) {
  1057.     if (!insert)
  1058.         PutStr (IM);
  1059.     } else if (insert)
  1060.     PutStr (EI);
  1061.     insert = on;
  1062. }
  1063.  
  1064. /* ...and maybe keypad application mode is a toggle, too:
  1065.  */
  1066. static KeypadMode (on) {
  1067.     if (on) {
  1068.     if (!keypad)
  1069.         PutStr (KS);
  1070.     } else if (keypad)
  1071.     PutStr (KE);
  1072.     keypad = on;
  1073. }
  1074.  
  1075. static DesignateCharset (c, n) {
  1076.     curr->ss = 0;
  1077.     if (c == 'B')
  1078.     c = ASCII;
  1079.     if (curr->charsets[n] != c) {
  1080.     curr->charsets[n] = c;
  1081.     if (curr->LocalCharset == n) {
  1082.         NewCharset (GlobalCharset, c);
  1083.         GlobalCharset = c;
  1084.     }
  1085.     }
  1086. }
  1087.  
  1088. static MapCharset (n) {
  1089.     curr->ss = 0;
  1090.     if (curr->LocalCharset != n) {
  1091.     curr->LocalCharset = n;
  1092.     NewCharset (GlobalCharset, curr->charsets[n]);
  1093.     GlobalCharset = curr->charsets[n];
  1094.     }
  1095. }
  1096.  
  1097. static NewCharset (old, new) {
  1098.     char buf[8];
  1099.  
  1100.     if (old == new)
  1101.     return;
  1102.     if (ISO2022) {
  1103.     sprintf (buf, "\033(%c", new == ASCII ? 'B' : new);
  1104.     PutStr (buf);
  1105.     }
  1106. }
  1107.  
  1108. static SaveCursor () {
  1109.     curr->saved = 1;
  1110.     curr->Saved_x = curr->x;
  1111.     curr->Saved_y = curr->y;
  1112.     curr->SavedLocalAttr = curr->LocalAttr;
  1113.     curr->SavedLocalCharset = curr->LocalCharset;
  1114.     bcopy ((char *)curr->charsets, (char *)curr->SavedCharsets,
  1115.     4 * sizeof (int));
  1116. }
  1117.  
  1118. static RestoreCursor () {
  1119.     if (curr->saved) {
  1120.     curr->LocalAttr = curr->SavedLocalAttr;
  1121.     NewRendition (GlobalAttr, curr->LocalAttr);
  1122.     GlobalAttr = curr->LocalAttr;
  1123.     bcopy ((char *)curr->SavedCharsets, (char *)curr->charsets,
  1124.         4 * sizeof (int));
  1125.     curr->LocalCharset = curr->SavedLocalCharset;
  1126.     NewCharset (GlobalCharset, curr->charsets[curr->LocalCharset]);
  1127.     GlobalCharset = curr->charsets[curr->LocalCharset];
  1128.     Goto (curr->y, curr->x, curr->Saved_y, curr->Saved_x);
  1129.     curr->x = curr->Saved_x;
  1130.     curr->y = curr->Saved_y;
  1131.     }
  1132. }
  1133.  
  1134. /*ARGSUSED*/
  1135. static CountChars (c) {
  1136.     StrCost++;
  1137. }
  1138.  
  1139. static CalcCost (s) register char *s; {
  1140.     if (s) {
  1141.     StrCost = 0;
  1142.     tputs (s, 1, CountChars);
  1143.     return StrCost;
  1144.     } else return EXPENSIVE;
  1145. }
  1146.  
  1147. static Goto (y1, x1, y2, x2) {
  1148.     register dy, dx;
  1149.     register cost = 0;
  1150.     register char *s;
  1151.     int CMcost, n, m;
  1152.     enum move_t xm = M_NONE, ym = M_NONE;
  1153.  
  1154.     if (!display)
  1155.     return;
  1156.     if (x1 == cols || x2 == cols) {
  1157.     if (x2 == cols) --x2;
  1158.     goto DoCM;
  1159.     }
  1160.     dx = x2 - x1;
  1161.     dy = y2 - y1;
  1162.     if (dy == 0 && dx == 0)
  1163.     return;
  1164.     if (y1 == -1 || x1 == -1 || y2 >= curr->bot || y2 <= curr->top) {
  1165. DoCM:
  1166.     PutStr (tgoto (CM, x2, y2));
  1167.     return;
  1168.     }
  1169.     CMcost = CalcCost (tgoto (CM, x2, y2));
  1170.     if (dx > 0) {
  1171.     if ((n = RewriteCost (y1, x1, x2)) < (m = dx * NDcost)) {
  1172.         cost = n;
  1173.         xm = M_RW;
  1174.     } else {
  1175.         cost = m;
  1176.         xm = M_RI;
  1177.     }
  1178.     } else if (dx < 0) {
  1179.     cost = -dx * LEcost;
  1180.     xm = M_LE;
  1181.     }
  1182.     if (dx && (n = RewriteCost (y1, 0, x2) + CRcost) < cost) {
  1183.     cost = n;
  1184.     xm = M_CR;
  1185.     }
  1186.     if (cost >= CMcost)
  1187.     goto DoCM;
  1188.     if (dy > 0) {
  1189.     cost += dy * DOcost;
  1190.     ym = M_DO;
  1191.     } else if (dy < 0) {
  1192.     cost += -dy * UPcost;
  1193.     ym = M_UP;
  1194.     }
  1195.     if (cost >= CMcost)
  1196.     goto DoCM;
  1197.     if (xm != M_NONE) {
  1198.     if (xm == M_LE || xm == M_RI) {
  1199.         if (xm == M_LE) {
  1200.         s = BC; dx = -dx;
  1201.         } else s = ND;
  1202.         while (dx-- > 0)
  1203.         PutStr (s);
  1204.     } else {
  1205.         if (xm == M_CR) {
  1206.         PutStr (CR);
  1207.         x1 = 0;
  1208.         }
  1209.         if (x1 < x2) {
  1210.         if (curr->insert)
  1211.             InsertMode (0);
  1212.         for (s = curr->image[y1]+x1; x1 < x2; x1++, s++)
  1213.             putchar (*s);
  1214.         if (curr->insert)
  1215.             InsertMode (1);
  1216.         }
  1217.     }
  1218.     }
  1219.     if (ym != M_NONE) {
  1220.     if (ym == M_UP) {
  1221.         s = UP; dy = -dy;
  1222.     } else s = DO;
  1223.     while (dy-- > 0)
  1224.         PutStr (s);
  1225.     }
  1226. }
  1227.  
  1228. static RewriteCost (y, x1, x2) {
  1229.     register cost, dx;
  1230.     register char *p = curr->attr[y]+x1, *f = curr->font[y]+x1;
  1231.  
  1232.     if (AM && y == rows-1 && x2 == cols-1)
  1233.     return EXPENSIVE;
  1234.     cost = dx = x2 - x1;
  1235.     if (dx == 0)
  1236.     return 0;
  1237.     if (curr->insert)
  1238.     cost += EIcost + IMcost;
  1239.     do {
  1240.     if (*p++ != GlobalAttr || *f++ != GlobalCharset)
  1241.         return EXPENSIVE;
  1242.     } while (--dx);
  1243.     return cost;
  1244. }
  1245.  
  1246. static BackSpace () {
  1247.     if (curr->x > 0) {
  1248.     if (curr->x < cols) {
  1249.         if (BC)
  1250.         PutStr (BC);
  1251.         else
  1252.         Goto (curr->y, curr->x, curr->y, curr->x-1);
  1253.     }
  1254.     curr->x--;
  1255.     }
  1256. }
  1257.  
  1258. static Return () {
  1259.     if (curr->x > 0) {
  1260.     curr->x = 0;
  1261.     PutStr (CR);
  1262.     }
  1263. }
  1264.  
  1265. static LineFeed () {
  1266.     if (curr->y == curr->bot) {
  1267.     ScrollUpMap (curr->image);
  1268.     ScrollUpMap (curr->attr);
  1269.     ScrollUpMap (curr->font);
  1270.     } else if (curr->y < rows-1) {
  1271.     curr->y++;
  1272.     }
  1273.     PutStr (NL);
  1274. }
  1275.  
  1276. static ReverseLineFeed () {
  1277.     if (curr->y == curr->top) {
  1278.     ScrollDownMap (curr->image);
  1279.     ScrollDownMap (curr->attr);
  1280.     ScrollDownMap (curr->font);
  1281.     if (SR) {
  1282.         PutStr (SR);
  1283.     } else if (AL) {
  1284.         Goto (curr->top, curr->x, curr->top, 0);
  1285.         PutStr (AL);
  1286.         Goto (curr->top, 0, curr->top, curr->x);
  1287.     } else Redisplay ();
  1288.     } else if (curr->y > 0) {
  1289.     CursorUp (1);
  1290.     }
  1291. }
  1292.  
  1293. static InsertAChar (c) {
  1294.     register y = curr->y, x = curr->x;
  1295.  
  1296.     if (x == cols)
  1297.     x--;
  1298.     bcopy (curr->image[y], OldImage, cols);
  1299.     bcopy (curr->attr[y], OldAttr, cols);
  1300.     bcopy (curr->font[y], OldFont, cols);
  1301.     bcopy (curr->image[y]+x, curr->image[y]+x+1, cols-x-1);
  1302.     bcopy (curr->attr[y]+x, curr->attr[y]+x+1, cols-x-1);
  1303.     bcopy (curr->font[y]+x, curr->font[y]+x+1, cols-x-1);
  1304.     SetChar (c);
  1305.     if (!display)
  1306.     return;
  1307.     if (IC || IM) {
  1308.     if (!curr->insert)
  1309.         InsertMode (1);
  1310.     PutStr (IC);
  1311.     putchar (c);
  1312.     if (!curr->insert)
  1313.         InsertMode (0);
  1314.     } else {
  1315.     RedisplayLine (OldImage, OldAttr, OldFont, y, x, cols-1);
  1316.     ++x;
  1317.     Goto (y, last_x, y, x);
  1318.     }
  1319. }
  1320.  
  1321. static InsertChar (n) {
  1322.     register i, y = curr->y, x = curr->x;
  1323.  
  1324.     if (x == cols)
  1325.     return;
  1326.     bcopy (curr->image[y], OldImage, cols);
  1327.     bcopy (curr->attr[y], OldAttr, cols);
  1328.     bcopy (curr->font[y], OldFont, cols);
  1329.     if (n > cols-x)
  1330.     n = cols-x;
  1331.     bcopy (curr->image[y]+x, curr->image[y]+x+n, cols-x-n);
  1332.     bcopy (curr->attr[y]+x, curr->attr[y]+x+n, cols-x-n);
  1333.     bcopy (curr->font[y]+x, curr->font[y]+x+n, cols-x-n);
  1334.     ClearInLine (0, y, x, x+n-1);
  1335.     if (!display)
  1336.     return;
  1337.     if (IC || IM) {
  1338.     if (!curr->insert)
  1339.         InsertMode (1);
  1340.     for (i = n; i; i--) {
  1341.         PutStr (IC);
  1342.         putchar (' ');
  1343.     }
  1344.     if (!curr->insert)
  1345.         InsertMode (0);
  1346.     Goto (y, x+n, y, x);
  1347.     } else {
  1348.     RedisplayLine (OldImage, OldAttr, OldFont, y, x, cols-1);
  1349.     Goto (y, last_x, y, x);
  1350.     }
  1351. }
  1352.  
  1353. static DeleteChar (n) {
  1354.     register i, y = curr->y, x = curr->x;
  1355.  
  1356.     if (x == cols)
  1357.     return;
  1358.     bcopy (curr->image[y], OldImage, cols);
  1359.     bcopy (curr->attr[y], OldAttr, cols);
  1360.     bcopy (curr->font[y], OldFont, cols);
  1361.     if (n > cols-x)
  1362.     n = cols-x;
  1363.     bcopy (curr->image[y]+x+n, curr->image[y]+x, cols-x-n);
  1364.     bcopy (curr->attr[y]+x+n, curr->attr[y]+x, cols-x-n);
  1365.     bcopy (curr->font[y]+x+n, curr->font[y]+x, cols-x-n);
  1366.     ClearInLine (0, y, cols-n, cols-1);
  1367.     if (!display)
  1368.     return;
  1369.     if (CDC && !(n == 1 && DC)) {
  1370.     CPutStr (CDC, n);
  1371.     } else if (DC) {
  1372.     for (i = n; i; i--)
  1373.         PutStr (DC);
  1374.     } else {
  1375.     RedisplayLine (OldImage, OldAttr, OldFont, y, x, cols-1);
  1376.     Goto (y, last_x, y, x);
  1377.     }
  1378. }
  1379.  
  1380. static DeleteLine (n) {
  1381.     register i, old = curr->top;
  1382.  
  1383.     if (n > curr->bot-curr->y+1)
  1384.     n = curr->bot-curr->y+1;
  1385.     curr->top = curr->y;
  1386.     for (i = n; i; i--) {
  1387.     ScrollUpMap (curr->image);
  1388.     ScrollUpMap (curr->attr);
  1389.     ScrollUpMap (curr->font);
  1390.     }
  1391.     if (DL || CDL) {
  1392.     Goto (curr->y, curr->x, curr->y, 0);
  1393.     if (CDL && !(n == 1 && DL)) {
  1394.         CPutStr (CDL, n);
  1395.     } else {
  1396.         for (i = n; i; i--)
  1397.         PutStr (DL);
  1398.     }
  1399.     Goto (curr->y, 0, curr->y, curr->x);
  1400.     } else if (CS) {
  1401.     PutStr (tgoto (CS, curr->bot, curr->top));
  1402.     Goto (-1, -1, curr->bot, 0);
  1403.     for (i = n; i; i--)
  1404.         PutStr (SF);
  1405.     PutStr (tgoto (CS, curr->bot, old));
  1406.     Goto (-1, -1, curr->y, curr->x);
  1407.     } else Redisplay ();
  1408.     curr->top = old;
  1409. }
  1410.  
  1411. static InsertLine (n) {
  1412.     register i, old = curr->top;
  1413.  
  1414.     if (n > curr->bot-curr->y+1)
  1415.     n = curr->bot-curr->y+1;
  1416.     curr->top = curr->y;
  1417.     for (i = n; i; i--) {
  1418.     ScrollDownMap (curr->image);
  1419.     ScrollDownMap (curr->attr);
  1420.     ScrollDownMap (curr->font);
  1421.     }
  1422.     if (AL || CAL) {
  1423.     Goto (curr->y, curr->x, curr->y, 0);
  1424.     if (CAL && !(n == 1 && AL)) {
  1425.         CPutStr (CAL, n);
  1426.     } else {
  1427.         for (i = n; i; i--)
  1428.         PutStr (AL);
  1429.     }
  1430.     Goto (curr->y, 0, curr->y, curr->x);
  1431.     } else if (CS && SR) {
  1432.     PutStr (tgoto (CS, curr->bot, curr->top));
  1433.     Goto (-1, -1, curr->y, 0);
  1434.     for (i = n; i; i--)
  1435.         PutStr (SR);
  1436.     PutStr (tgoto (CS, curr->bot, old));
  1437.     Goto (-1, -1, curr->y, curr->x);
  1438.     } else Redisplay ();
  1439.     curr->top = old;
  1440. }
  1441.  
  1442. static ScrollUpMap (pp) char **pp; {
  1443.     register char *tmp = pp[curr->top];
  1444.  
  1445.     bcopy ((char *)(pp+curr->top+1), (char *)(pp+curr->top),
  1446.     (curr->bot-curr->top) * sizeof (char *));
  1447.     if (pp == curr->image)
  1448.     bclear (tmp, cols);
  1449.     else
  1450.     bzero (tmp, cols);
  1451.     pp[curr->bot] = tmp;
  1452. }
  1453.  
  1454. static ScrollDownMap (pp) char **pp; {
  1455.     register char *tmp = pp[curr->bot];
  1456.  
  1457.     bcopy ((char *)(pp+curr->top), (char *)(pp+curr->top+1),
  1458.     (curr->bot-curr->top) * sizeof (char *));
  1459.     if (pp == curr->image)
  1460.     bclear (tmp, cols);
  1461.     else
  1462.     bzero (tmp, cols);
  1463.     pp[curr->top] = tmp;
  1464. }
  1465.  
  1466. static ForwardTab () {
  1467.     register x = curr->x;
  1468.  
  1469.     if (curr->tabs[x] && x < cols-1)
  1470.     ++x;
  1471.     while (x < cols-1 && !curr->tabs[x])
  1472.     x++;
  1473.     Goto (curr->y, curr->x, curr->y, x);
  1474.     curr->x = x;
  1475. }
  1476.  
  1477. static BackwardTab () {
  1478.     register x = curr->x;
  1479.  
  1480.     if (curr->tabs[x] && x > 0)
  1481.     x--;
  1482.     while (x > 0 && !curr->tabs[x])
  1483.     x--;
  1484.     Goto (curr->y, curr->x, curr->y, x);
  1485.     curr->x = x;
  1486. }
  1487.  
  1488. static ClearScreen () {
  1489.     register i;
  1490.  
  1491.     PutStr (CL);
  1492.     for (i = 0; i < rows; ++i) {
  1493.     bclear (curr->image[i], cols);
  1494.     bzero (curr->attr[i], cols);
  1495.     bzero (curr->font[i], cols);
  1496.     }
  1497. }
  1498.  
  1499. static ClearFromBOS () {
  1500.     register n, y = curr->y, x = curr->x;
  1501.  
  1502.     for (n = 0; n < y; ++n)
  1503.     ClearInLine (1, n, 0, cols-1);
  1504.     ClearInLine (1, y, 0, x);
  1505.     Goto (curr->y, curr->x, y, x);
  1506.     curr->y = y; curr->x = x;
  1507. }
  1508.  
  1509. static ClearToEOS () {
  1510.     register n, y = curr->y, x = curr->x;
  1511.  
  1512.     if (CD)
  1513.     PutStr (CD);
  1514.     ClearInLine (!CD, y, x, cols-1);
  1515.     for (n = y+1; n < rows; n++)
  1516.     ClearInLine (!CD, n, 0, cols-1);
  1517.     Goto (curr->y, curr->x, y, x);
  1518.     curr->y = y; curr->x = x;
  1519. }
  1520.  
  1521. static ClearLine () {
  1522.     register y = curr->y, x = curr->x;
  1523.  
  1524.     ClearInLine (1, y, 0, cols-1);
  1525.     Goto (curr->y, curr->x, y, x);
  1526.     curr->y = y; curr->x = x;
  1527. }
  1528.  
  1529. static ClearToEOL () {
  1530.     register y = curr->y, x = curr->x;
  1531.  
  1532.     ClearInLine (1, y, x, cols-1);
  1533.     Goto (curr->y, curr->x, y, x);
  1534.     curr->y = y; curr->x = x;
  1535. }
  1536.  
  1537. static ClearFromBOL () {
  1538.     register y = curr->y, x = curr->x;
  1539.  
  1540.     ClearInLine (1, y, 0, x);
  1541.     Goto (curr->y, curr->x, y, x);
  1542.     curr->y = y; curr->x = x;
  1543. }
  1544.  
  1545. static ClearInLine (displ, y, x1, x2) {
  1546.     register i, n;
  1547.  
  1548.     if (x1 == cols) x1--;
  1549.     if (x2 == cols) x2--;
  1550.     if (n = x2 - x1 + 1) {
  1551.     bclear (curr->image[y]+x1, n);
  1552.     bzero (curr->attr[y]+x1, n);
  1553.     bzero (curr->font[y]+x1, n);
  1554.     if (displ && display) {
  1555.         if (x2 == cols-1 && CE) {
  1556.         Goto (curr->y, curr->x, y, x1);
  1557.         curr->y = y; curr->x = x1;
  1558.         PutStr (CE);
  1559.         return;
  1560.         }
  1561.         if (y == rows-1 && AM)
  1562.         --n;
  1563.         if (n == 0)
  1564.         return;
  1565.         SaveAttr (0);
  1566.         Goto (curr->y, curr->x, y, x1);
  1567.         for (i = n; i > 0; i--)
  1568.         putchar (' ');
  1569.         curr->y = y; curr->x = x1 + n;
  1570.         RestoreAttr (0);
  1571.     }
  1572.     }
  1573. }
  1574.  
  1575. static CursorRight (n) register n; {
  1576.     register x = curr->x;
  1577.  
  1578.     if (x == cols)
  1579.     return;
  1580.     if ((curr->x += n) >= cols)
  1581.     curr->x = cols-1;
  1582.     Goto (curr->y, x, curr->y, curr->x);
  1583. }
  1584.  
  1585. static CursorUp (n) register n; {
  1586.     register y = curr->y;
  1587.  
  1588.     if ((curr->y -= n) < curr->top)
  1589.     curr->y = curr->top;
  1590.     Goto (y, curr->x, curr->y, curr->x);
  1591. }
  1592.  
  1593. static CursorDown (n) register n; {
  1594.     register y = curr->y;
  1595.  
  1596.     if ((curr->y += n) > curr->bot)
  1597.     curr->y = curr->bot;
  1598.     Goto (y, curr->x, curr->y, curr->x);
  1599. }
  1600.  
  1601. static CursorLeft (n) register n; {
  1602.     register x = curr->x;
  1603.  
  1604.     if ((curr->x -= n) < 0)
  1605.     curr->x = 0;
  1606.     Goto (curr->y, x, curr->y, curr->x);
  1607. }
  1608.  
  1609. static SetMode (on) {
  1610.     register i;
  1611.  
  1612.     for (i = 0; i < curr->NumArgs; ++i) {
  1613.     switch (curr->args[i]) {
  1614.     case 4:
  1615.         curr->insert = on;
  1616.         InsertMode (on);
  1617.         break;
  1618.     }
  1619.     }
  1620. }
  1621.  
  1622. static SelectRendition () {
  1623.     register i, old = GlobalAttr;
  1624.  
  1625.     if (curr->NumArgs == 0)
  1626.     SetRendition (0);
  1627.     else for (i = 0; i < curr->NumArgs; ++i)
  1628.     SetRendition (curr->args[i]);
  1629.     NewRendition (old, GlobalAttr);
  1630. }
  1631.  
  1632. static SetRendition (n) register n; {
  1633.     switch (n) {
  1634.     case 0:
  1635.     GlobalAttr = 0; break;
  1636.     case 1:
  1637.     GlobalAttr |= A_BD; break;
  1638.     case 2:
  1639.     GlobalAttr |= A_DI; break;
  1640.     case 3:
  1641.     GlobalAttr |= A_SO; break;
  1642.     case 4:
  1643.     GlobalAttr |= A_US; break;
  1644.     case 5:
  1645.     GlobalAttr |= A_BL; break;
  1646.     case 7:
  1647.     GlobalAttr |= A_RV; break;
  1648.     case 22:
  1649.     GlobalAttr &= ~(A_BD|A_SO|A_DI); break;
  1650.     case 23:
  1651.     GlobalAttr &= ~A_SO; break;
  1652.     case 24:
  1653.     GlobalAttr &= ~A_US; break;
  1654.     case 25:
  1655.     GlobalAttr &= ~A_BL; break;
  1656.     case 27:
  1657.     GlobalAttr &= ~A_RV; break;
  1658.     }
  1659.     curr->LocalAttr = GlobalAttr;
  1660. }
  1661.  
  1662. static NewRendition (old, new) register old, new; {
  1663.     register i;
  1664.  
  1665.     if (old == new)
  1666.     return;
  1667.     for (i = 1; i <= A_MAX; i <<= 1) {
  1668.     if ((old & i) && !(new & i)) {
  1669.         PutStr (UE);
  1670.         PutStr (SE);
  1671.         PutStr (ME);
  1672.         if (new & A_US) PutStr (US);
  1673.         if (new & A_SO) PutStr (SO);
  1674.         if (new & A_BL) PutStr (MB);
  1675.         if (new & A_BD) PutStr (MD);
  1676.         if (new & A_DI) PutStr (MH);
  1677.         if (new & A_RV) PutStr (MR);
  1678.         return;
  1679.     }
  1680.     }
  1681.     if ((new & A_US) && !(old & A_US))
  1682.     PutStr (US);
  1683.     if ((new & A_SO) && !(old & A_SO))
  1684.     PutStr (SO);
  1685.     if ((new & A_BL) && !(old & A_BL))
  1686.     PutStr (MB);
  1687.     if ((new & A_BD) && !(old & A_BD))
  1688.     PutStr (MD);
  1689.     if ((new & A_DI) && !(old & A_DI))
  1690.     PutStr (MH);
  1691.     if ((new & A_RV) && !(old & A_RV))
  1692.     PutStr (MR);
  1693. }
  1694.  
  1695. static SaveAttr (newattr) {
  1696.     NewRendition (GlobalAttr, newattr);
  1697.     NewCharset (GlobalCharset, ASCII);
  1698.     if (curr->insert)
  1699.     InsertMode (0);
  1700. }
  1701.  
  1702. static RestoreAttr (oldattr) {
  1703.     NewRendition (oldattr, GlobalAttr);
  1704.     NewCharset (ASCII, GlobalCharset);
  1705.     if (curr->insert)
  1706.     InsertMode (1);
  1707. }
  1708.  
  1709. static FillWithEs () {
  1710.     register i;
  1711.     register char *p, *ep;
  1712.  
  1713.     curr->y = curr->x = 0;
  1714.     SaveAttr (0);
  1715.     for (i = 0; i < rows; ++i) {
  1716.     bzero (curr->attr[i], cols);
  1717.     bzero (curr->font[i], cols);
  1718.     p = curr->image[i];
  1719.     ep = p + cols;
  1720.     for ( ; p < ep; ++p)
  1721.         *p = 'E';
  1722.     }
  1723.     RestoreAttr (0);
  1724.     Redisplay ();
  1725. }
  1726.  
  1727. static Redisplay () {
  1728.     register i;
  1729.  
  1730.     PutStr (CL);
  1731.     TmpAttr = GlobalAttr;
  1732.     TmpCharset = GlobalCharset;
  1733.     InsertMode (0);
  1734.     last_x = last_y = 0;
  1735.     for (i = 0; i < rows; ++i)
  1736.     DisplayLine (blank, null, null, curr->image[i], curr->attr[i],
  1737.         curr->font[i], i, 0, cols-1);
  1738.     if (curr->insert)
  1739.     InsertMode (1);
  1740.     NewRendition (TmpAttr, GlobalAttr);
  1741.     NewCharset (TmpCharset, GlobalCharset);
  1742.     Goto (last_y, last_x, curr->y, curr->x);
  1743. }
  1744.  
  1745. static DisplayLine (os, oa, of, s, as, fs, y, from, to)
  1746.     register char *os, *oa, *of, *s, *as, *fs; {
  1747.     register i, x, a, f;
  1748.  
  1749.     if (to == cols)
  1750.     --to;
  1751.     if (AM && y == rows-1 && to == cols-1)
  1752.     --to;
  1753.     a = TmpAttr;
  1754.     f = TmpCharset;
  1755.     for (x = i = from; i <= to; ++i, ++x) {
  1756.     if (s[i] == os[i] && as[i] == oa[i] && as[i] == a
  1757.                   && of[i] == fs[i] && fs[i] == f)
  1758.         continue;
  1759.     Goto (last_y, last_x, y, x);
  1760.     last_y = y;
  1761.     last_x = x;
  1762.     if ((a = as[i]) != TmpAttr) {
  1763.         NewRendition (TmpAttr, a);
  1764.         TmpAttr = a;
  1765.     }
  1766.     if ((f = fs[i]) != TmpCharset) {
  1767.         NewCharset (TmpCharset, f);
  1768.         TmpCharset = f;
  1769.     }
  1770.     putchar (s[i]);
  1771.     last_x++;
  1772.     }
  1773. }
  1774.  
  1775. static RedisplayLine (os, oa, of, y, from, to) char *os, *oa, *of; {
  1776.     if (curr->insert)
  1777.     InsertMode (0);
  1778.     NewRendition (GlobalAttr, 0);
  1779.     TmpAttr = 0;
  1780.     NewCharset (GlobalCharset, ASCII);
  1781.     TmpCharset = ASCII;
  1782.     last_y = y;
  1783.     last_x = from;
  1784.     DisplayLine (os, oa, of, curr->image[y], curr->attr[y],
  1785.     curr->font[y], y, from, to);
  1786.     NewRendition (TmpAttr, GlobalAttr);
  1787.     NewCharset (TmpCharset, GlobalCharset);
  1788.     if (curr->insert)
  1789.     InsertMode (1);
  1790. }
  1791.  
  1792. static MakeBlankLine (p, n) register char *p; register n; {
  1793.     do *p++ = ' ';
  1794.     while (--n);
  1795. }
  1796.  
  1797. MakeStatus (msg, wp) char *msg; struct win *wp; {
  1798.     struct win *ocurr = curr;
  1799.     int odisplay = display;
  1800.     register char *s, *t;
  1801.     register max = AM ? cols-1 : cols;
  1802.  
  1803.     for (s = t = msg; *s && t - msg < max; ++s)
  1804.     if (*s >= ' ' && *s <= '~')
  1805.         *t++ = *s;
  1806.     *t = '\0';
  1807.     curr = wp;
  1808.     display = 1;
  1809.     if (status) {
  1810.     if (time ((time_t *)0) - TimeDisplayed < 2)
  1811.         sleep (1);
  1812.     RemoveStatus (wp);
  1813.     }
  1814.     if (t > msg) {
  1815.     status = 1;
  1816.     StatLen = t - msg;
  1817.     Goto (curr->y, curr->x, rows-1, 0);
  1818.     SaveAttr (A_SO);
  1819.     printf ("%s", msg);
  1820.     RestoreAttr (A_SO);
  1821.     (void) fflush (stdout);
  1822.     time (&TimeDisplayed);
  1823.     }
  1824.     curr = ocurr;
  1825.     display = odisplay;
  1826. }
  1827.  
  1828. RemoveStatus (p) struct win *p; {
  1829.     struct win *ocurr = curr;
  1830.     int odisplay = display;
  1831.  
  1832.     if (!status)
  1833.     return;
  1834.     status = 0;
  1835.     curr = p;
  1836.     display = 1;
  1837.     Goto (-1, -1, rows-1, 0);
  1838.     RedisplayLine (null, null, null, rows-1, 0, StatLen);
  1839.     Goto (rows-1, last_x, curr->y, curr->x);
  1840.     curr = ocurr;
  1841.     display = odisplay;
  1842. }
  1843. SHAR_EOF
  1844. if test 35918 -ne "`wc -c < 'ansi.c'`"
  1845. then
  1846.     echo shar: error transmitting "'ansi.c'" '(should have been 35918 characters)'
  1847. fi
  1848. fi # end of overwriting check
  1849. echo shar: extracting "'screen.h'" '(2247 characters)'
  1850. if test -f 'screen.h'
  1851. then
  1852.     echo shar: will not over-write existing file "'screen.h'"
  1853. else
  1854. cat << \SHAR_EOF > 'screen.h'
  1855. /* Copyright (c) 1987,1988 Oliver Laumann, Technical University of Berlin.
  1856.  * Not derived from licensed software.
  1857.  *
  1858.  * Permission is granted to freely use, copy, modify, and redistribute
  1859.  * this software, provided that no attempt is made to gain profit from it,
  1860.  * the author is not construed to be liable for any results of using the
  1861.  * software, alterations are clearly marked as such, and this notice is
  1862.  * not modified.
  1863.  */
  1864.  
  1865. enum state_t {
  1866.     LIT,         /* Literal input */
  1867.     ESC,         /* Start of escape sequence */
  1868.     STR,         /* Start of control string */
  1869.     TERM,        /* ESC seen in control string */
  1870.     CSI,         /* Reading arguments in "CSI Pn ; Pn ; ... ; XXX" */
  1871.     PRIN,        /* Printer mode */
  1872.     PRINESC,     /* ESC seen in printer mode */
  1873.     PRINCSI,     /* CSI seen in printer mode */
  1874.     PRIN4        /* CSI 4 seen in printer mode */
  1875. };
  1876.  
  1877. enum string_t {
  1878.     NONE,
  1879.     DCS,         /* Device control string */
  1880.     OSC,         /* Operating system command */
  1881.     APC,         /* Application program command */
  1882.     PM,          /* Privacy message */
  1883. };
  1884.  
  1885. #define MAXSTR       128
  1886. #define    MAXARGS      64
  1887.  
  1888. #define IOSIZE       80
  1889.  
  1890. struct win {
  1891.     int wpid;
  1892.     int ptyfd;
  1893.     int aflag;
  1894.     char outbuf[IOSIZE];
  1895.     int outlen;
  1896.     char cmd[MAXSTR];
  1897.     char tty[MAXSTR];
  1898.     int args[MAXARGS];
  1899.     char GotArg[MAXARGS];
  1900.     int NumArgs;
  1901.     int slot;
  1902.     char **image;
  1903.     char **attr;
  1904.     char **font;
  1905.     int LocalCharset;
  1906.     int charsets[4];
  1907.     int ss;
  1908.     int active;
  1909.     int x, y;
  1910.     char LocalAttr;
  1911.     int saved;
  1912.     int Saved_x, Saved_y;
  1913.     char SavedLocalAttr;
  1914.     int SavedLocalCharset;
  1915.     int SavedCharsets[4];
  1916.     int top, bot;
  1917.     int wrap;
  1918.     int origin;
  1919.     int insert;
  1920.     int keypad;
  1921.     enum state_t state;
  1922.     enum string_t StringType;
  1923.     char string[MAXSTR];
  1924.     char *stringp;
  1925.     char *tabs;
  1926.     int vbwait;
  1927.     int bell;
  1928. };
  1929.  
  1930. #define MAXLINE 1024
  1931.  
  1932. #define MSG_CREATE    0
  1933. #define MSG_ERROR     1
  1934. #define MSG_ATTACH    2
  1935. #define MSG_CONT      3
  1936.  
  1937. struct msg {
  1938.     int type;
  1939.     union {
  1940.     struct {
  1941.         int aflag;
  1942.         int nargs;
  1943.         char line[MAXLINE];
  1944.         char dir[1024];
  1945.     } create;
  1946.     struct {
  1947.         int apid;
  1948.         char tty[1024];
  1949.     } attach;
  1950.     char message[MAXLINE];
  1951.     } m;
  1952. };
  1953. SHAR_EOF
  1954. if test 2247 -ne "`wc -c < 'screen.h'`"
  1955. then
  1956.     echo shar: error transmitting "'screen.h'" '(should have been 2247 characters)'
  1957. fi
  1958. fi # end of overwriting check
  1959. #    End of shell archive
  1960. exit 0
  1961.  
  1962.  
  1963.